(define-module (sudoku board)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-9)
  #:use-module (sudoku square)
  #:export (board
            make-board board?
            board-array set-board-array!))

(define-record-type <board>
  (make-board array)
  board?
  (array board-array set-board-array!))

(define-public (make-9x9-board)
  (let ((dimension 9))
    (make-board
     (make-square-array (make-square dimension)
                        dimension))))

(define (make-square-array fill dimension)
  (make-array fill dimension dimension))

(define-public (set-square! board square i j)
  (array-set! (board-array board) square i j))

(define-public (get-row board i)
  (let loop ((j 0) (row '()))
    (if (array-in-bounds? (board-array board) i j)
      (loop (1+ j)
            (cons (array-ref (board-array board) i j) row))
      (reverse row))))

(define-public (set-row! board row i)
  (for-each (lambda (square j)
              (array-set! (board-array board)
                          square i j))
            row
            (iota 9)))

(define-public (get-col board j)
  (let loop ((i 0) (col '()))
    (if (array-in-bounds? (board-array board) i j)
      (loop (1+ i)
            (cons (array-ref (board-array board) i j) col))
      (reverse col))))

(define-public (set-col! board col j)
  (for-each (lambda (square i)
              (array-set! (board-array board) square i j))
            col
            (iota 9)))

(define-public (get-box board n)
  (let ((x (* 3 (quotient n 3)))
        (y (* 3 (modulo n 3))))
    (reverse
      (fold (lambda (i l)
              (cons (array-ref
                     (board-array board)
                     (+ x (quotient i 3))
                     (+ y (modulo i 3)))
                    l))
            '()
            (iota 9)))))

;;; TODO: add cut support
(define-public (set-box! board box n)
  (let ((x (* 3 (quotient n 3)))
        (y (* 3 (modulo n 3))))
    (for-each (lambda (square i)
                (array-set! (board-array board)
                            square
                            (+ x (quotient i 3))
                            (+ y (modulo i 3))))
              box
              (iota 9))))
